package org.clockworkmages.games.anno1186.gui;

import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javax.swing.JTextPane;
import javax.swing.Timer;
import javax.swing.text.StyledDocument;

import org.clockworkmages.games.anno1186.model.common.Pair;

public class AnimatedTextPane
		extends JTextPane implements ActionListener {
	private Map<String, AnimatedImage> images = new LinkedHashMap<String, AnimatedImage>();

	private Timer timer;

	private long lastPerformed = System.currentTimeMillis();

	private List<Pair<String, String>> infoTextAndFontIdBuffer = new ArrayList<Pair<String, String>>();

	public AnimatedTextPane() {
		this(true);
	}

	public AnimatedTextPane(boolean animated) {
		super();
		setOpaque(false);
		if (animated) {
			timer = new Timer(50, this);
			timer.setInitialDelay(100);
			timer.start();
			this.addComponentListener(new ComponentAdapter() {
				@Override
				public void componentResized(final ComponentEvent e) {
					for (AnimatedImage animatedImage : images.values()) {
						// TODO
					}
					AnimatedTextPane.this.repaint();
				}
			});
		}
	}

	public Map<String, AnimatedImage> getImages() {
		return images;
	}

	@Override
	public void paintComponent(final Graphics g) {

		long interval = System.currentTimeMillis() - lastPerformed;
		lastPerformed = System.currentTimeMillis();
		for (AnimatedImage animatedImage : images.values()) {
			animatedImage.update(interval);
			animatedImage.draw(g, this);
		}
		super.paintComponent(g);
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		this.repaint();
	}

	public void clearText() {
		StyledDocument doc = getStyledDocument();
		try {
			doc.remove(0, doc.getLength());
		} catch (Exception e) {
			GameUiUtil.logError(e);
		}
	}

	public void removeTrailing(String trailingCharacters) {
		StyledDocument doc = getStyledDocument();
		try {
			String text = doc.getText(0, doc.getLength());
			// check for last index, in case there's e.g. an empty space after
			// the trailing character
			int lastIndex = text.lastIndexOf(trailingCharacters);
			if (lastIndex > -1) {
				doc.remove(lastIndex, doc.getLength() - lastIndex);
			}
		} catch (Exception e) {
			GameUiUtil.logError(e);
		}
	}

	public void appendText(String message) {
		String[] as = message.split("\\{f");

		for (String s : as) {
			String fontStyleId;
			String text;
			int endOfFontDefinition = s.indexOf("}");
			if (endOfFontDefinition == -1) {
				// assume that's the last font-per-text definition in the text:
				text = s;
				fontStyleId = FontStyleConstants.REGULAR;
			} else if (endOfFontDefinition == 0) {
				// the {f} tag which means we should switch from whatever
				// special font was being used before to the regular font.
				text = s.substring(endOfFontDefinition + 1);
				fontStyleId = FontStyleConstants.REGULAR;
			} else {
				// something like {f:b}, which means we should switch to the
				// special font:
				text = s.substring(endOfFontDefinition + 1);
				if (!s.startsWith(":")) {
					// not good, that's some incorrect definition
					GameUiUtil
							.logError("Unrecognizable font definition in the text: {f"
									+ s);
					fontStyleId = FontStyleConstants.REGULAR;
				} else {
					fontStyleId = s.substring(1, endOfFontDefinition);
				}
			}
			appendText(text, fontStyleId);
		}
	}

	public synchronized void appendText(String message, String fontStyleId) {
		StyledDocument doc = getStyledDocument();
		try {
			doc.insertString(doc.getLength(), message,
					doc.getStyle(fontStyleId));
		} catch (Exception e) {
			GameUiUtil.logError(e);
		}
	}

	public void addInfoToBuffer(String infoText) {
		this.infoTextAndFontIdBuffer.add(new Pair<String, String>(infoText,
				FontStyleConstants.RED_BOLD));
	}

	public void addInfoToBuffer(String infoText, String fontStyleId) {
		this.infoTextAndFontIdBuffer.add(new Pair<String, String>(infoText,
				fontStyleId));
	}

	public void flushInfoBuffer() {
		for (Pair<String, String> infoTextAndFontStyleId : this.infoTextAndFontIdBuffer) {
			appendText(infoTextAndFontStyleId.getFirst(),
					infoTextAndFontStyleId.getSecond());
		}
		this.infoTextAndFontIdBuffer.clear();
	}

}
